# -*- coding: utf-8 -*-
import socket
import fcntl
import struct
import array


class IFConfig:
    """Pozwala odczytać informacje o interfejsach sieciowych
        takie jak adres IP oraz maska podsieci"""
    def __init__(self):
        pass
   # offsety znalezione w /usr/include/linux/sockios.h (linux 2.6)
    @staticmethod 
    def get_ip_address(ifname):
        """
        Queries Linux kernel for IP addres of the particular interface
        chosen by passing mandatory "ifname" argument. Returns string 
        containing IP addres in dotted-decimal format (eg. '4.2.2.2')
        """
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(
            s.fileno(),
            0x8915, # SIOCGIFADDR
            struct.pack('256s', ifname[:15])
        )[20:24])
    @staticmethod
    def get_netmask(ifname, long=False):
        """
        Queries Linux kernel for netmask of the interface "ifname".
        ifname argument should be given as a canonical name of the network interface
        such as "eth0", "lo" etc. Method returns string containing netmask value
        in one of two well known formats. If you pass True value as "long" argument
        it will return netmask in long format (e.g. '255.255.255.0'). Otherwise
        If you give 'False' value as "long" argument it will return netmask of
        the interface in CIDR notation (eg. '/24') 
        """
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        mask =  socket.inet_ntoa(fcntl.ioctl(s.fileno(),
                 0x891b,
                 struct.pack('256s', ifname[:15]))[20:24])
        if long:
            return mask
        else:
            return IFConfig.long2cidr(mask)
            
    @staticmethod
    def get_ifaces_up():
        """
        Queries Linux kernel for structure containing various information about
        installed network interfaces. Returns list of strings with names of
        interfaces (only those that are currently in the "up" state).
        """
        max_ifaces = 128
        bytes = 32 * max_ifaces
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        ifnames = array.array('B', '\0' * bytes)
        out = struct.unpack('iL', fcntl.ioctl(s.fileno(), 0x8912, struct.pack('iL', bytes, ifnames.buffer_info()[0])))[0]
        names_human = ifnames.tostring()
        return [names_human[i:i+32].split('\0', 1)[0] for i in range(0, out, 32)]
    @staticmethod
    def long2cidr(longmask):
        """
        Converts specified network mask in long format to CIDR (Classless Inter-Domain Routing)
        format. For example if you pass "255.255.255.0" string as an argument, it will return string
        "/24"
        """
        import re,math
        m = re.match("^(\d+)\.(\d+)\.(\d+)\.(\d+)", longmask)
        return sum([ 8 - int(math.log(256-int(x),2)) for x in m.groups()])